package hut.ai.team.actor;

import hut.ai.team.object.QuanCo;
import hut.ai.team.screen.MainScreen;
import hut.ai.team.table.NuocDi;
import hut.ai.team.table.VanCo;

import java.util.ArrayList;

public class Computer extends Player {
	public static int deep = 1;
	public NuocDi newmove = new NuocDi();
	ArrayList<NuocDi> arrMoveAI = new ArrayList<NuocDi>();
	ArrayList<NuocDi> arrMoveHuman = new ArrayList<NuocDi>();
	public static final int INFINITY = 99999;
	public Gen mGen;

	public Computer(int x) {
		super(x);
		this.dsQuanCo = new ArrayList<QuanCo>();
		this.mQC = new QuanCo();
		this.Phe = x;
		this.mGen = new Gen();
		this.KhoiTao();
	}
	
	// --------------------- Ham reset Computer
	public void ResetComputer() {
		newmove = new NuocDi();
		dsQuanCo = new ArrayList<QuanCo>();
		mQC = new QuanCo();
	}

	// --------------------- Ham thuc hien nuoc di cua Computer
	public synchronized void ComputerThink() {
		System.out.println("Luot di: " + VanCo.LuotDi);
		if (VanCo.LuotDi == MainScreen.getInstance().computer.Phe) {
			if (MainScreen.getInstance().computer != null) {
				AlphaBeta(Computer.deep, -INFINITY, INFINITY, VanCo.LuotDi);
//				AlphaBeta(-INFINITY, INFINITY, Computer.deep);
				if (newmove.Dau.TrangThai != 0) {
					// Thiet lap nuoc di o day
					System.out.print("AI move Dau:    [" + newmove.Dau.Hang + "," 
					+ newmove.Dau.Cot + "," + newmove.Dau.Phe + "," + newmove.Dau.TrangThai + "," +newmove.Dau.Loai +"]");
					
					System.out.print("AI move Cuoi:    [" + newmove.Cuoi.Hang + "," 
							+ newmove.Cuoi.Cot + "," + newmove.Cuoi.Phe + "," + newmove.Cuoi.TrangThai + "," +newmove.Cuoi.Loai +"]");
					for (int i = 0; i < MainScreen.getInstance().computer.dsQuanCo.size(); i++) {
						if (newmove.Dau.Hang == MainScreen.getInstance().computer.dsQuanCo.get(i).Hang	
								&& newmove.Dau.Cot == MainScreen.getInstance().computer.dsQuanCo.get(i).Cot) {
							VanCo.DanhDau = MainScreen.getInstance().computer.dsQuanCo.get(i);
							break;
						}
					}
					int hc = newmove.Cuoi.Hang;
					int cc = newmove.Cuoi.Cot;
					// Ô cờ trống tại ví trí ban đầu
					MainScreen.getInstance().mBanCo.OCoTrong(VanCo.DanhDau.Hang, VanCo.DanhDau.Cot);
					// Đặt quân cờ đã chọn vào vị trí mới
					VanCo.DatQuanCo(VanCo.DanhDau, hc, cc);
					if (newmove.Cuoi.TrangThai != 0) {
						VanCo.AnQuanCo(newmove.Cuoi);
					}
					// Thay đổi lượt đi
					VanCo.DoiLuotDi();
					// Kiểm tra chiếu bí
					VanCo.KiemTraChieuBi();
				} else {
					VanCo.winner = 1;
				}
				if (VanCo.winner != 2) {
					if (MainScreen.getInstance().mode == 2) {
						if (VanCo.winner == 0) MainScreen.getInstance().dialog.show("Player red has winner");
						if (VanCo.winner == 1) MainScreen.getInstance().dialog.show("Player black has winner");
						MainScreen.getInstance().dialog.setVisible(true);
					} else {
						if (VanCo.winner == 0) MainScreen.getInstance().dialog.show("Computer has winner");
						if (VanCo.winner == 1) MainScreen.getInstance().dialog.show("Player 1 has winner");
						MainScreen.getInstance().dialog.setVisible(true);
					}
					MainScreen.getInstance().mBanCo.KhoaBanCo();
				}
				// Kiểm tra chiếu tướng
				VanCo.KiemTraChieuTuong();
				MainScreen.getInstance().mBanCo.ResetCanMove();
				System.out.println();
				System.out.println("Sau khi AI move");
				MainScreen.getInstance().mBanCo.showData();
			}
		}
	}
	
	public int AlphaBeta(int depth,int alpha,int beta,int luotdi){
//		System.out.println("AI: [" + depth + "," + alpha + "," + beta + "," + luotdi + "]");
		if(depth <= 0){
			Eval mEval = new Eval();
			int diem = Math.abs(mEval.UocLuong());
			return diem;
		}
		if(luotdi == 2){
			ArrayList<NuocDi> arrMoveAI = mGen.SinhNuocDiChoAI();
			for(int i = 0; i < arrMoveAI.size(); i++){
				try {
					mGen.MakeMove(arrMoveAI.get(i));
//					MainScreen.getInstance().mBanCo.showData();
					alpha = Math.min(beta, AlphaBeta(depth - 1, alpha, beta, VanCo.LuotDi));
					mGen.UnMakeMove(arrMoveAI.get(i));
//					System.out.println("UnMakeMove");
//					MainScreen.getInstance().mBanCo.showData();
					if(depth == Computer.deep)
//	                    newmove = arrMoveAI.get(i);
						getBestMove(arrMoveAI);
					if(beta <= alpha){
						break;
					}
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
			return alpha;
		}else{
			ArrayList<NuocDi> arrMoveHuman = mGen.SinhNuocChoNguoiChoi();
			System.out.println("Size nuoc di sinh ra cua Nguoi choi: " + arrMoveHuman.size());
			for(int i = 0; i < arrMoveHuman.size(); i++){
				try {
					mGen.MakeMove(arrMoveHuman.get(i));
					MainScreen.getInstance().mBanCo.showData();
					beta = Math.max(alpha, AlphaBeta(depth - 1, alpha, beta, VanCo.LuotDi));
					mGen.UnMakeMove(arrMoveHuman.get(i));
					MainScreen.getInstance().mBanCo.showData();
					if(beta <= alpha){
						break;
					}
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
			return beta;
		}
	}
	
	public void getBestMove(ArrayList<NuocDi> arrMove){
		int min = arrMove.get(0).score;
		for(int i = 0; i < arrMove.size(); i++){
			int diem = arrMove.get(i).score;
			System.out.println("[" + diem + "," + min + "]["+ arrMove.get(i).Dau.Hang +"," + arrMove.get(i).Dau.Cot +"," + arrMove.get(i).Dau.Phe +"," + arrMove.get(i).Dau.TrangThai + "," + arrMove.get(i).Dau.Loai + "]");
			if( diem < min){
				min = diem;
				newmove = arrMove.get(i);
			}
		}
	}
	
	public int AlphaBeta(int alpha, int beta, int deep)
    {
		int best = -INFINITY;
        int value;
        ArrayList<NuocDi> nm = mGen.SinhNuocDi();
        for (int i = 0; i < nm.size() && best < beta; i++)
        {
	        if (deep < 0){
	        	Eval mEval = new Eval();
	        	return mEval.UocLuong();
	        }
	        else
	        {
	        	mGen.MakeMove(nm.get(i));
                value = -AlphaBeta(-beta, -alpha, deep - 1);
                mGen.UnMakeMove(nm.get(i));
                if(value > best)
                	best = value;
                if(best > alpha)
                	alpha = best;
                if(alpha >= beta)
                	return alpha;
                if(deep == Computer.deep)
                	newmove = nm.get(i);
            }          
        }
        return best;
    }

}
